
#ifndef __THREAD_POOL_  // 避免头文件重复包含
#define __THREAD_POOL_  

#include <iostream>
#include "LockGuard.hpp"
#include <unistd.h>
// #include "Task.hpp"
#include <vector>
#include "Thread.hpp"
#include <queue>
#include <mutex>
#include "Log.hpp"
#include <mutex>

// #define REALSE 1  //开启RELSE版本下的日志记录模式
#define THREADPOOL_NUM 5  //默认线程池数


template <class T> //T 为任务类型
class ThreadPool
{
public:
    //为类外提供私有成员接口
    bool get_queue_empty(){return task_->empty();}

    pthread_mutex_t* get_mutex(){return &mtx_;}

    // 获取当前头任务
    T get_task()
    {
        auto ret = task_->front();
        // std::cout <<"ret" <<  ret << std::endl;
        task_->pop();
        return ret; 
        // 主线程已经将内容删除了，只保留了任务队列上的，因此
        // 这个对象将需要传值返回
    }

    // 开始等待信号量
    void wait_cond(){pthread_cond_wait(&cond_, &mtx_);}

public:

    // 多线程处理函数——重要函数
    static void* routine(void* trda)  
    // 关于 routine函数，要设置为静态的原因：
    // 在Thread构造中，第二位为void*(*func_t)(void*)类型
    // 而类中成员函数都隐藏了一个this指针，这样会导致routine类型不匹配的问题
    {
        ThreadDate* _trda = static_cast<ThreadDate*>(trda);
        ThreadPool<T>* th = static_cast<ThreadPool<T>*>(_trda->args); 
        T task;
        while (1)  //不断获取任务
        {
            {
            LockGuard lk(th->get_mutex()); //自己封装的一个加锁类
            while (th->get_queue_empty()) 
            {
                th->wait_cond();
            }
            task = th->get_task();  //获取任务，执行...
            }
            (*task)();
            // sleep(1);
        }
        return nullptr;
    }

    // 通过该指令加载
    static ThreadPool<T>* Get_Instance(int num = THREADPOOL_NUM)
    {
        if (st == nullptr)
        {
            mutex_inital.lock();
            if (st == nullptr)
            {
              st =  new ThreadPool<T>(num);
            }
            mutex_inital.unlock();
        }

        return st;
    }

    // 线程池启动
    void Run()
    {
        for (auto& e : _thr_pool)
        {
            e->start();
        }
        Logmessage(INFO,"thread pool run success");
    }

    void push(const T& ta) // 向任务队列中载入任务
    {
        //LockGuard lk(&mtx_);  使用备用栈就没有竞争访问的问题
        //lk.lockguard();
        task_reserver->push(ta); 
        //pthread_cond_signal(&cond_);
    } 

    void show()
    {
        std::cout << "外部调用成功" << std::endl;
    }

    ~ThreadPool()
    {   
        for (auto& e : _thr_pool)
        {
            e->join();
            delete(e);
        }
        delete task_;
        delete task_reserver;
    }

    void swap_queue(int QUEUE_TASK_NUM)
    {
        if (st->Get_queue_task_reserver_size() >= QUEUE_TASK_NUM / 2  &&
            st->Get_queue_task_size() == 0 &&
            st->Get_queue_task_reserver_size() <= QUEUE_TASK_NUM)
        {
            LockGuard lk(&mtx_);
        lk.lockguard();
        task_->swap(*task_reserver);
        pthread_cond_broadcast(&cond_);
        }
    }
    
    int Get_queue_task_size(){return task_->size();}
    
    int Get_queue_task_reserver_size(){return task_reserver->size();}

    ThreadPool<T>(const ThreadPool<T>& it) = delete;

    ThreadPool<T>& operator= (const ThreadPool<T>& it) = delete;

private:
    ThreadPool(int num = THREADPOOL_NUM):_pnum(num), task_(new std::queue<T>),
         task_reserver(new std::queue<T>)
    {
        for (int i = 0; i < num; i++)
        {
            _thr_pool.push_back(new Thread(i + 1, routine, this));
            // 考虑到处理方法可能还会获取进程池的信息，因此我们将进程池传入
        }

        pthread_mutex_init(&mtx_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }

    std::vector<Thread*> _thr_pool;
    int _pnum;  // 有效线程数

    std::queue<T>* task_;
    std::queue<T>* task_reserver;

    pthread_mutex_t mtx_;
    pthread_cond_t cond_; // 估计就是设置的资源量

    static ThreadPool<T>* st;
    static std::mutex mutex_inital; //这里直接用C++的锁,防止覆盖锁
};

template <class T>
ThreadPool<T>* ThreadPool<T>::st = nullptr;
template <class T>
std::mutex ThreadPool<T>::mutex_inital;

#endif


